 /* ---------------------------------------------------------------------
 * player.c
 *
 * Functions dealing with player interaction, including:
 *
 * - User input processing
 * - Windowing into the movie
 * - The control panel
 * - player shots
 * --------------------------------------------------------------------*/

#define _PLAYER_

#include <io.h>
#include <i86.h>
#include <fcntl.h>
#include <dos.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <mem.h>
#include <ctype.h>

#include "rad.h"

#include "player.h"
#include "mouse.h"
#include "sprite.h"
#include "event.h"
#include "sound.h"
#include "palette.h"
#include "xenon.h"
#include "debug.h"
#include "keyboard.h"

//#define CHUKWUWETA      1

#define TRUE 1
#define FALSE 0

// Some of the nasty player information globals.  Some are in player.h.
// This could use a bit of tidying up (ie, transfer them all to player.h)
extern long     g_branchframe;
extern char     g_cutsceneon;
extern char     g_typeofdeath;
extern long     g_seekto;
extern long     g_curframe;
extern long     g_numberofframes;
extern long     g_nextscenenumber;
extern long     g_currentscenenumber;
extern JOYDATA  g_joydata;
extern char     g_selectedtool,g_selectedweap;
extern char g_incyberspace;
extern TARGET  *g_SpritesOnScreen;
extern TARGET   g_targstack[];
extern TARGETCLASS g_classtack[];
extern void SpriteAddOnScreen(long spritenum, TARGET * spritetarg);
extern int LoadSprites(char *name,long palettebase,long numcolors);

unsigned char   g_goslow = 0;
long g_damgstar_x, g_damgstar_y;
long g_shotready = SHOT_NONE;    // What kind of shot should be fired

long g_inputdevice;  /* User input device in use */
long g_userbuttons = 0;      /* State of user input device buttons */
mousestate g_mousestate;   // State of the mouse

long  g_deltax;       /* change in x position of input device */
long  g_deltay;       /* change in y position,etc. */
long  g_shipshake;    // Decrementing counter to shake the frame up

short  g_totaldh, g_totaldv;  /* One whole frame worth of mouse deltas */

long *g_coordbuf;     // Buffer containing player sprite
		       // information, like
	    // where the center and wingtips are located.
long g_deathSceneGoto = 0;   // the Default death will go to
			     // gendeath then the main menu
long g_deathFrameGoto = 0;

int xJoyMax = 1;
int yJoyMax = 1;
int xJoyMin = 500;
int yJoyMin = 500;

sprite        *g_ramsprites;

// -----------------------------------------------------------------------
//   Function Prototypes
//   (Could use some updating)
// -----------------------------------------------------------------------
extern void     drawline(long, long, long, long, u8 *, long, long);
long            random(long n);
unsigned char   Get_Scan_Code(void);

// -----------------------------------------------------------------------
//   Function Definitions
// -----------------------------------------------------------------------
int  getmousedeltas();
void loadcoords();
void findshipposition();
int  setwindowoffset();
long random(long n);
int  initplayerinfo();
int  processkeyboard();
BOOL checktool(short px, short py);
void movetopdown();
int  testcollisionmap(u8 * picbuf);
int  checkforcollision(u8 * buf);
void changeWeap(void);
void changeTool(void);
void checkWeapShot(short px, short py);

/* -------------------------------------------------------------------
 * processuserinput
 *
 * Checks the inputdevice for movement and adjusts the screen accordingly.
 * ------------------------------------------------------------------*/

processuserinput(u8 * smackbuf)
{
    static buttonhold = FALSE;

	 if (smackbuf != (u8 *)NULL)
	    processkeyboard();

    switch (g_inputdevice) 
	 {
		case INPUT_MOUSE:
			getmousedeltas();
			break;
		case INPUT_JOY:
			getJoyPos();
			break;
    }

	 if (smackbuf == (u8 *)NULL)
		return(1);

    /* Adjust player position */
    switch (g_viewmode) 
	 {
    case VIEW_FIRSTPERSON:      // This should be a seperate function
	// Clip DX and DY to maximum values
	if (g_deltax < -2 * MAXDX)
	    g_deltax = -2 * MAXDX;
	if (g_deltax > 2 * MAXDX)
	    g_deltax = 2 * MAXDX;
	if (g_deltay < -2 * MAXDY)
	    g_deltay = -2 * MAXDY;
	if (g_deltay > 2 * MAXDY)
	    g_deltay = 2 * MAXDY;

	// Adjust player's position
			if (g_inputdevice == INPUT_MOUSE)
			{
		g_player.x += g_deltax;
//#ifndef CHUKWUWETA
	     g_player.y += g_deltay;
//#else
//	   g_player.y -= g_deltay; // Note y-axis reversed-pilot's stick
//#endif
			}
			else            
			{
				if (g_deltax < 3 && g_deltax > -4)
					g_deltax = 0;
				g_player.x += g_deltax;
				if (g_deltay < 3 && g_deltay > -4)
					g_deltay = 0;
				g_player.y -= g_deltay; // Note that y-axis is reversed (pilot's
				  // stick)
			}

	// Keep the player's coords within bounds
	if (g_player.x < FIRST_MAX_LEFT)
	    g_player.x = FIRST_MAX_LEFT;
	else if (g_player.x > FIRST_MAX_RIGHT)
	    g_player.x = FIRST_MAX_RIGHT;
	if (g_player.y < FIRST_MAX_TOP)
	    g_player.y = FIRST_MAX_TOP;
	else if (g_player.y > FIRST_MAX_BOTTOM)
	    g_player.y = FIRST_MAX_BOTTOM;

			// Targeting cursor = player position in VIEW_FIRSTPERSON
			g_player.tcx = g_player.x;
			if (g_inputdevice == INPUT_MOUSE)
			{
				g_player.tcy = g_player.y;
			}
			else
			{
				if (g_player.y > 80)
					g_player.tcy = (80 - (g_player.y - 80));
				else if (g_player.y < 80)
					g_player.tcy = (80 + (80 - g_player.y));
				else if (g_player.y == 80)
					g_player.tcy = g_player.y;
			}
	break;

    case VIEW_TOPDOWN:
	movetopdown();
	break;

    case VIEW_RWDSHIP:
	findshipposition();
	break;

    case VIEW_CYBSHIP:
	findshipposition();
	break;

    default:
	break;
    }

    // Get status of mouse/joystick buttons
    if (g_userbuttons && !buttonhold) 
	 {
	if (g_userbuttons == 2)
	    g_shotready = SHOT_TOOL;
	else
	    g_shotready = SHOT_WEAPON;
	buttonhold = TRUE;
    }
    if (!g_userbuttons)
	buttonhold = FALSE;

	// Set the g_windowx,g_windowy variables
    setwindowoffset();
    checkforcollision(smackbuf);
	 return(TRUE);
}

// ----------------------------------------------------------------------
//  getmousedeltas()
//
//  Check for changes mouse position and button status
// ----------------------------------------------------------------------

getmousedeltas()
{
    /* Get current state of mouse */
    mouseStatus((mousestateptr) & g_mousestate.button);

    /* Get deviance of mouse from center */
    g_deltax = (g_mousestate.x - MOUSECENTERX);
    g_deltay = (g_mousestate.y - MOUSECENTERY);

    /* Restore mouse pointer (invisible) to center */
    moveMouse(MOUSECENTERX, MOUSECENTERY);
    /* Set state of buttons */
    g_userbuttons = g_mousestate.button & 7;
	 return(TRUE);
}

// -------------------------------------------------------------------
//  loadcoords()
//
//  Load coordinates of the following points on the player's ship
//  sprites:  The left wingtip, the center of the sprite, and the right
//  wingtip.
// -------------------------------------------------------------------

void loadcoords()
{
    long fh;
    long coordbufsize = 49 * 6 * sizeof(long);
    if (!g_coordbuf) 
	 {
	if (!(g_coordbuf = (long *) malloc(coordbufsize))) 
		  {
	    fatalerror("Couldn't allocate coordbuf");
	}
    }
//#ifndef CHUKWUWETA
	 sprintf(g_buffer, "%s\\data\\coords.bin",g_cdrom);
//#else
//	 sprintf(g_buffer, "c\:\\data\\coords.bin",g_cdrom);
//#endif
    fh = open(g_buffer, O_RDONLY | O_BINARY);
    if (fh < 0) 
	 {
	fatalerror("Couldn't Open coords.bin");
    }
    read(fh, g_coordbuf, coordbufsize);
    close(fh);
}

/*--------------------------------------------------------------------
 * findshipposition
 *
 * Finds the new ship position based on a mouse-delta.  This is an old
 * function that works in VIEW_RWDSHIP mode only!
-------------------------------------------------------------------- */

void findshipposition()
{
	int whichsprite=0, turnadjustment=0, bankadjustment = 0;

	if (g_turndataready) 
	 {
		extern long      g_curframe;
		turnadjustment = g_turntable[g_curframe];
		bankadjustment = (0 - turnadjustment) / 2;
	}
	/* Adjust player position, velocity */
	g_deltay /= DYPERMICKEY;
	g_deltax /= DXPERMICKEY;
	if (g_deltax < -1 * MAXDX)
		g_deltax = -1 * MAXDX;
	if (g_deltax > MAXDX)
		g_deltax = MAXDX;
	if (g_deltay < -1 * MAXDY)
		g_deltay = -1 * MAXDY;
	if (g_deltay > MAXDY)
		g_deltay = MAXDY;

	g_player.dx += g_deltax;
	if (g_inputdevice == INPUT_JOY)
		g_player.dy -= g_deltay;        /* Note dy is reversed (pilot's stick) */
	else
//#ifndef CHUKWUWETA
		g_player.dy += g_deltay;        /* Note dy is not reversed (pilot's stick) */
//#else
//		g_player.dy -= g_deltay;        /* Note dy is reversed (pilot's stick) */
//#endif
	g_player.x += g_player.dx + turnadjustment;
	g_player.y += g_player.dy;

	/* Check boundaries */
	if (g_player.x < SHIP_MAX_LEFT) 
	 {
		g_player.x = SHIP_MAX_LEFT;
		g_player.dx = 0;
	} 
	 else if (g_player.x > SHIP_MAX_RIGHT) 
	 {
		g_player.x = SHIP_MAX_RIGHT;
		g_player.dx = 0;
	}
	if (g_player.y < SHIP_MAX_TOP) 
	 {
		g_player.y = SHIP_MAX_TOP;
		g_player.dy = 0;
	}
	if (g_player.y < SHIP_MAX_TOP + 24 && (g_player.bank > 2 || g_player.bank < -2)) 
	 {
		g_player.y = SHIP_MAX_TOP + 24;
		g_player.dy = 0;
	} 
	 else if (g_player.y > SHIP_MAX_BOTTOM) 
	 {
		g_player.y = SHIP_MAX_BOTTOM;
		g_player.dy = 0;
	}
	// Adjust the pitch (angle of the nose up/down) and
	// the bank (angle of the wings relative to a line through the ship)
	g_player.pitch = g_player.dy / 2;
	if (g_player.pitch < -3)
		g_player.pitch = -3;
	if (g_player.pitch > 3)
		g_player.pitch = 3;
	g_player.bank = g_player.dx / 3 + bankadjustment;
	if (bankadjustment < 0) 
	 {
		if (g_player.bank > bankadjustment)
			g_player.bank = bankadjustment;
	}
	if (bankadjustment > 0) 
	 {
		if (g_player.bank < bankadjustment)
			g_player.bank = bankadjustment;
	}
	if (g_player.bank < -3)
		g_player.bank = -3;
	if (g_player.bank > 3)
		g_player.bank = 3;

	// Adjust the cpitch (current pitch) and cbank.  The cpitch and cbank
	// will move toward desired pitch and bank at a rate of 1 per frame.
	// This has the effect of smooth rolls, etc.

	if (g_player.cpitch < g_player.pitch)
		g_player.cpitch++;
	else if (g_player.cpitch > g_player.pitch)
		g_player.cpitch--;
	if (g_player.cbank < g_player.bank)
		g_player.cbank++;
	else if (g_player.cbank > g_player.bank)
		g_player.cbank--;

	// Apply friction to slow down the movement of the ship over time.
	g_player.dx = (3 * g_player.dx) / 4;
	g_player.dy = (3 * g_player.dy) / 4;

	/* Determine location of targeting cursor */
	// Note: this should be relative to the nose of the ship!  Since
	// the ship doesn't yaw (ie, the nose doesn't move left or right),
	// the cursor only moves up and down in relation to the pitch.
	g_player.tcx = g_player.x + 1;
	g_player.tcy = g_player.y + 10 * g_player.cpitch - 14;

	if (g_player.tcy < 10)
		g_player.tcy = 10;
	else if (g_player.tcy > 150)
		g_player.tcy = 150;

	/* Zero out movement counters */
	g_deltax = 0;
	g_deltay = 0;

	// Determine which sprite to display based on current pitch and bank,
	// then determine coordinates of wings and center.
	whichsprite = 17 + g_player.cpitch * 7 - g_player.cbank;
	if (whichsprite < 0)
		whichsprite = 0;
	else if (whichsprite > 48)
		whichsprite = 48;
	g_player.offx = g_coordbuf[(whichsprite) * 6 + 2];
	g_player.offy = g_coordbuf[(whichsprite) * 6 + 3];
	g_player.cursprite = whichsprite + 1;
	g_player.leftwingx = g_player.x - g_player.offx + g_coordbuf[whichsprite * 6];
	g_player.rightwingx = g_player.x - g_player.offx + g_coordbuf[whichsprite * 6 + 4];
	if (g_viewmode == VIEW_FIRSTPERSON) 
	 {
		g_player.leftwingy = g_player.y - g_player.offy + g_coordbuf[whichsprite * 6 + 1];
		g_player.rightwingy = g_player.y - g_player.offy + g_coordbuf[whichsprite * 6 + 5];
	} 
	 else 
	 {      // other wise it's VIEW_CYBERSHIP or VIEW_RWDSHIP!
		g_player.leftwingy = ((g_player.y - g_player.offy + g_coordbuf[whichsprite * 6 + 1]) - 10);
		g_player.rightwingy = ((g_player.y - g_player.offy + g_coordbuf[whichsprite * 6 + 5]) - 10);
		if (g_inputdevice == INPUT_JOY)
		{
			g_joyplayer.x = g_player.x;
			g_joyplayer.dx = g_player.dx;
			g_joyplayer.dy = (g_player.dy * -1);
			if (g_player.y > 80)
				g_joyplayer.y = (80 - (g_player.y - 80));
			else if (g_player.y < 80)
				g_joyplayer.y = (80 + (80 - g_player.y));
			else if (g_player.y == 80)
				g_player.y = g_joyplayer.y;
			// Adjust the pitch (angle of the nose up/down) and
			// the bank (angle of the wings relative to a line through the ship)
//                      g_joyplayer.pitch = g_joyplayer.dy / 2;
			g_joyplayer.pitch = g_joyplayer.dy * 2;
			if (g_joyplayer.pitch < -3)
				g_joyplayer.pitch = -3;
			if (g_joyplayer.pitch > 3)
				g_joyplayer.pitch = 3;
			g_joyplayer.bank = g_joyplayer.dx / 3 + bankadjustment;
			if (bankadjustment < 0) 
			{
				if (g_joyplayer.bank > bankadjustment)
					g_joyplayer.bank = bankadjustment;
			}
			if (bankadjustment > 0) 
			{
				if (g_joyplayer.bank < bankadjustment)
					g_joyplayer.bank = bankadjustment;
			}
			if (g_joyplayer.bank < -3)
				g_joyplayer.bank = -3;
			if (g_joyplayer.bank > 3)
				g_joyplayer.bank = 3;

	// Adjust the cpitch (current pitch) and cbank.  The cpitch and cbank
	// will move toward desired pitch and bank at a rate of 1 per frame.
	// This has the effect of smooth rolls, etc.

			if (g_joyplayer.cpitch < g_joyplayer.pitch)
				g_joyplayer.cpitch++;
			else if (g_joyplayer.cpitch > g_joyplayer.pitch)
				g_joyplayer.cpitch--;
			if (g_joyplayer.cbank < g_joyplayer.bank)
				g_joyplayer.cbank++;
			else if (g_joyplayer.cbank > g_joyplayer.bank)
				g_joyplayer.cbank--;

		// Apply friction to slow down the movement of the ship over time.
			g_joyplayer.dx = (3 * g_joyplayer.dx) / 4;
			g_joyplayer.dy = (3 * g_joyplayer.dy) / 4;

			g_joyplayer.tcx = g_joyplayer.x + 1;
			g_joyplayer.tcy = g_joyplayer.y + 10 * g_joyplayer.cpitch - 14;

			if (g_joyplayer.tcy < 10)
				g_joyplayer.tcy = 10;
			else if (g_joyplayer.tcy > 150)
				g_joyplayer.tcy = 150;

			// Determine which sprite to display based on current pitch and bank,
			// then determine coordinates of wings and center.
			whichsprite = 17 + g_joyplayer.cpitch * 7 - g_joyplayer.cbank;
			if (whichsprite < 0)
				whichsprite = 0;
			else if (whichsprite > 48)
				whichsprite = 48;
			g_joyplayer.offx = g_coordbuf[(whichsprite) * 6 + 2];
			g_joyplayer.offy = g_coordbuf[(whichsprite) * 6 + 3];
			g_joyplayer.cursprite = whichsprite + 1;
			g_joyplayer.leftwingx = g_joyplayer.x - g_joyplayer.offx + g_coordbuf[whichsprite * 6];
			g_joyplayer.rightwingx = g_joyplayer.x - g_joyplayer.offx + g_coordbuf[whichsprite * 6 + 4];
			g_joyplayer.leftwingy = ((g_joyplayer.y - g_joyplayer.offy + g_coordbuf[whichsprite * 6 + 1]) - 10);
			g_joyplayer.rightwingy = ((g_joyplayer.y - g_joyplayer.offy + g_coordbuf[whichsprite * 6 + 5]) - 10);
		}
	}
}

// ----------------------------------------------------------------
//   setwindowoffset()
//
//  Do some math before setting the offset of the display window
// ----------------------------------------------------------------

setwindowoffset()
{
	short x, y;

	switch (g_viewmode) 
	 {
	case VIEW_FIRSTPERSON:
		x = (PAN_MUL_X * (g_player.x - FIRST_MAX_LEFT)) / PAN_DIV_X;
		  if (g_inputdevice == INPUT_JOY)
			y = (PAN_MUL_Y * (g_player.tcy - FIRST_MAX_TOP)) / PAN_DIV_Y;
		  else  
			y = (PAN_MUL_Y * (g_player.y - FIRST_MAX_TOP)) / PAN_DIV_Y;
		break;
	case VIEW_RWDSHIP:
	default:
		if (g_inputdevice == INPUT_JOY)
		{
			x = (PAN_MUL_X * (g_joyplayer.x - SHIP_MAX_LEFT)) / PAN_DIV_X;
			y = (PAN_MUL_Y * (g_joyplayer.y - SHIP_MAX_TOP)) / PAN_DIV_Y;
		}
		else
		{
			x = (PAN_MUL_X * (g_player.x - SHIP_MAX_LEFT)) / PAN_DIV_X;
			y = (PAN_MUL_Y * (g_player.y - SHIP_MAX_TOP)) / PAN_DIV_Y;
		}
		break;
	}
	g_windowx = x;
	g_windowy = y;
	if (g_shipshake) 
	 {
		g_windowx += (5 - random(10));
		g_windowy += (5 - random(10));
		if (g_windowx < 0)
			g_windowx = 0;
		if (g_windowy < 0)
			g_windowy = 0;
		if (g_windowx > 31)
			g_windowx = 31;
		if (g_windowy > 31)
			g_windowy = 31;
		g_shipshake--;
	}
	return(TRUE);
}
// -------------------------------------------------------------------
//   random()
//
//  Return a random integer between 0 and n-1, where n<=32767.
// -------------------------------------------------------------------

long random(long n)
{
	return (rand() * n / 32767);
}


/* ----------------------------------------------------------------------
 * playershot()
 *
 * Starts a shot from the player
 * ----------------------------------------------------------------------*/

#define SHOTFRAMES 4

void playershot(u8 * smackbuf)
{
	long shotcolor;

	if (g_shotready == SHOT_NONE)
		return;
	if ((g_shotready == SHOT_WEAPON) &&
		(g_selectedweap == WP_AiresMod || g_selectedweap == WP_AiresCom))
		return; // don't let them shoot with aires compiler or module.
	if (g_shotready == SHOT_WEAPON)
		shotcolor = SHOTCOLORBASE;
	else
		shotcolor = SHOTCOLORBASE + 1;
	switch (g_viewmode) 
	{
		case VIEW_FIRSTPERSON:
			if (g_shotready == SHOT_WEAPON) 
			{
				shotcolor =  g_weapcolors[g_selectedweap];
				drawline(20 , 160 , g_player.tcx - 4, g_player.tcy, smackbuf, 352, shotcolor);
				drawline(24 , 160, g_player.tcx - 4, g_player.tcy, smackbuf, 352, shotcolor);
				drawline(296, 160, g_player.tcx, g_player.tcy, smackbuf, 352, shotcolor);
				drawline(300, 160, g_player.tcx, g_player.tcy, smackbuf, 352, shotcolor);
				checkWeapShot(g_player.tcx + (short) g_windowx, g_player.tcy + (short) g_windowy);
			} 
			else if ((g_currentscenenumber > SC_GRWALL)  && 
			         (g_selectedtool != TL_DamageRepair))
			{
				shotcolor =  g_toolcolors[g_selectedtool];
				drawline(155, 160, g_player.tcx - 2, g_player.tcy, smackbuf, 352, shotcolor);
				drawline(160, 160, g_player.tcx - 2, g_player.tcy, smackbuf, 352, shotcolor);
				drawline(165, 160, g_player.tcx - 2, g_player.tcy, smackbuf, 352, shotcolor);
				checkToolShot(g_player.tcx + (short) g_windowx, g_player.tcy + (short) g_windowy);
			}
			break;

		default:
			if ((g_shotready == SHOT_WEAPON) || 
	   	  ((g_currentscenenumber > SC_GRWALL)  && 
			  (g_selectedtool !=TL_DamageRepair)))
			{
				if (g_shotready == SHOT_WEAPON) 
					shotcolor =  g_weapcolors[g_selectedweap];
				else
					shotcolor =  g_toolcolors[g_selectedtool];
			if (g_inputdevice == INPUT_JOY && g_currentscenenumber != SC_CITYLT)
			{
				if (g_currentscenenumber == SC_CANYON)
				{
					drawline(g_joyplayer.leftwingx+6, g_joyplayer.leftwingy +4, g_joyplayer.tcx -4,
							g_joyplayer.tcy, smackbuf, 352, shotcolor);
					drawline(g_joyplayer.rightwingx -6, g_joyplayer.rightwingy +4, g_joyplayer.tcx,
							g_joyplayer.tcy, smackbuf, 352, shotcolor);
				}
				else if (g_currentscenenumber == SC_PDEFEN)
				{
					drawline(g_joyplayer.leftwingx +6, g_joyplayer.leftwingy , g_joyplayer.tcx -4,
							g_joyplayer.tcy, smackbuf, 352, shotcolor);
					drawline(g_joyplayer.rightwingx-6, g_joyplayer.rightwingy , g_joyplayer.tcx,
							g_joyplayer.tcy, smackbuf, 352, shotcolor);
					}
				if (g_shotready == SHOT_WEAPON) 
				{
					checkWeapShot(g_joyplayer.tcx + (short) g_windowx, g_joyplayer.tcy + (short) g_windowy);
				} 		
				else 
				{
					checkToolShot(g_joyplayer.tcx + (short) g_windowx, g_joyplayer.tcy + (short) g_windowy);
				}		
			}
			else
			{
				if (g_currentscenenumber == SC_CANYON)
				{
					drawline(g_player.leftwingx + 6, g_player.leftwingy + 6, g_player.tcx -4,
								g_player.tcy, smackbuf, 352, shotcolor);
					drawline(g_player.rightwingx -4, g_player.rightwingy +6, g_player.tcx,
								g_player.tcy, smackbuf, 352, shotcolor);
				}
				else if (g_currentscenenumber == SC_PDEFEN)
				{
					drawline(g_player.leftwingx +6, g_player.leftwingy, g_player.tcx -4,
								g_player.tcy, smackbuf, 352, shotcolor);
					drawline(g_player.rightwingx -4, g_player.rightwingy, g_player.tcx,
								g_player.tcy, smackbuf, 352, shotcolor);
				}
				else if (g_currentscenenumber == SC_CITYLT)
				{
					drawline(g_player.leftwingx, g_player.leftwingy, g_player.tcx -4,
								g_player.tcy, smackbuf, 352, shotcolor);
					drawline(g_player.rightwingx, g_player.rightwingy, g_player.tcx,
								g_player.tcy, smackbuf, 352, shotcolor);
				}
				if (g_shotready == SHOT_WEAPON) 
				{	
					checkWeapShot(g_player.tcx + (short) g_windowx, g_player.tcy + (short) g_windowy);
				} 
				else 
				{
					checkToolShot(g_player.tcx + (short) g_windowx, g_player.tcy + (short) g_windowy);
				}
			}
		}
		break;
	}
	
	if (g_shotready == SHOT_WEAPON) 
	{
		playSoundFX(S_CYBERGUN);
	} 
	else 
	{
		if (g_currentscenenumber > SC_GRWALL)
			playSoundFX(S_TOOL);
	}
	g_shotready = SHOT_NONE;
}

// ----------------------------------------------------------------------
//   checkToolShot()
//
//  Check if player shots hit any tools or weaps, and pick them up
//  as necessary.
// ----------------------------------------------------------------------

void checkToolShot(short px, short py)
{
	short spritex, spritey;
	delayspriteptr  ds;
	spriteptr s;
	TARGET *targ, *links;
	long spritearea;
	static  long nexplfr=-1, uppermid =-1, lowermid =-1;
	static  long bigexpl=-1, smlexpl =-1,  midexpl=-1;
		
	nexplfr = (g_currentscenenumber > SC_GRWALL) ? NUMCYBEXPLFRAMES : NUMRWDEXPLFRAMES;
	bigexpl   = (g_currentscenenumber > SC_GRWALL) ? CBIG_EXPLOBASE : RBIG_EXPLOBASE;
	smlexpl   = (g_currentscenenumber > SC_GRWALL) ? CSML_EXPLOBASE : RSML_EXPLOBASE;
	midexpl   = (g_currentscenenumber > SC_GRWALL) ? CMID_EXPLOBASE : RMID_EXPLOBASE;

	uppermid  = g_sprsizes[g_currentscenenumber].average + 200;
	lowermid  = g_sprsizes[g_currentscenenumber].average - 200;

	// Check shot coords against bounding boxes of all the sprites
	// (Brute force, yes, but there are only 16 possibilities.)
	if (g_SpritesOnScreen == (TARGET *) NULL)
		return;

	if((g_selectedtool == TL_AccessTool) &&  
		(g_currentscenenumber > SC_INFNET) &&
		(g_currentscenenumber != SC_INWALL))
		return;

	for (targ = g_SpritesOnScreen; targ != (TARGET *) NULL; targ = targ->onscreen) 
	{
		if (targ->status.state != (short) STATE_ALIVE)
			continue;                  // Could be exploding

		if (targ->targettype == (long) TARGET_ENEMY)
			continue;

		ds = &g_pastein[targ->channel];
		spritex = ds->x;
		spritey = ds->y;
		s = ds->spritedata;
		if ((px > spritex) && (px < spritex + s->width) &&
			(py > spritey) && (py < spritey + s->height)) 
		{
			// A hit!
			targ->status.life -= g_classtack[targ->eclass].pdamage[g_tools[g_selectedtool].toolnum];
			if (targ->status.life <= 0)
				// If the shot destroys the target, make it go boom!
			{
				// Killed the sucker.
				targ->status.state = (short) STATE_DEAD;
				// SpriteDelOnScreen(targ);

				if (targ->targettype == TARGET_TOOL) 
				{
					if (targ->toolweapclue < MAX_CYBTOOLS) 
					{
						// Deal with sprites linked to this one
						for (links = targ->linkhead;
							 links != (TARGET *) NULL;
							 links = links->linked) 
						{
							if (links->status.state == (short) STATE_ALIVE)
								links->status.state = (short) STATE_DEAD;
							else if (links->status.state == (short) STATE_SLEEP) 
							{
								links->status.state = (short) STATE_ALIVE;
								SpriteAddOnScreen(-1, links);
							}
						}

						g_tools[targ->toolweapclue].toolaquired = TRUE;

						if((g_currentscenenumber == SC_INWALL) &&
						   (targ->toolweapclue == TL_Matrix)) 
						   {
						     sprintf(g_tools[TL_Matrix].toolname,"%s",
								"MATRIX DISRUPT");
							 g_selectedtool = TL_Matrix;
						   }
						if (targ->toolweapclue == TL_Passcode1) 
						{
							g_tools[TL_AccessTool].toolaquired = FALSE;
							if (g_selectedtool == TL_AccessTool)
								g_selectedtool = TL_Passcode1;
						}
						if (targ->toolweapclue == TL_Passcode2)
						{
							g_tools[TL_Passcode1].toolaquired = FALSE;
							if (g_selectedtool == TL_Passcode1)
								g_selectedtool = TL_Passcode2;
						}
						if (targ->toolweapclue == TL_TraceCutter2) 
						{
							playClue(1); //we're in infonet playing ha158.wav
						}
					playSoundFX(S_RETRIEVE);
						g_blinktxt.numframes = NUMBLINKFRAMES;
						sprintf(g_blinktxt.blinktext, " %s ACQUIRED\n",
								g_tools[targ->toolweapclue].toolname);
					} 
					else 
					{
						targ->status.state = (short)STATE_REST;
						for (links = targ->linkhead;
							 links != (TARGET *) NULL;
							 links = links->linked) 
						{
							if (links->status.state == (short) STATE_ALIVE)
								links->status.state = (short) STATE_REST;
							else if (links->status.state == (short) STATE_SLEEP) 
							{
								links->status.state = (short) STATE_ALIVE;
								SpriteAddOnScreen(-1, links);
							}
						}
					}
					if ((targ->toolweapclue == TL_Dogy)  ||
						(targ->toolweapclue == TL_Dtag)  ||
						(targ->toolweapclue == TL_Tornado))
					{
						targ->status.explosioncount = nexplfr;

					spritearea = (s->width * s->height);

					if(spritearea < lowermid)
					  targ->status.explosionsize = smlexpl;
					else if(spritearea > uppermid)
					  targ->status.explosionsize = bigexpl;
					else 
					  targ->status.explosionsize = midexpl;

						// stop the countdown if we git the doggy...
						if (g_currentscenenumber == SC_DATACL)
						{
							if (AIL_sample_status(smp[CLUE]) != SMP_DONE)
								AIL_end_sample(smp[CLUE]);
							if (!g_ponged)
							{
								g_ponged=TRUE;
								g_pongframe = (g_curframe + 10);
							}
						}
					}
				} 
				else if (targ->targettype == TARGET_WEAP) 
				{
					// Deal with sprites linked to this one
					for (links = targ->linkhead;
						 links != (TARGET *) NULL;
						 links = links->linked) 
					{
						if (links->status.state == (short) STATE_ALIVE)
							links->status.state = (short) STATE_DEAD;
						else if (links->status.state == (short) STATE_SLEEP) 
						{
							links->status.state = (short) STATE_ALIVE;
							SpriteAddOnScreen(-1, links);
						}
					}
					sprintf(g_blinktxt.blinktext, " %s ACQUIRED\n",
							g_weaps[targ->toolweapclue].weapname);
					g_numweaps++;  // increment total number of acquired weapons (for clue purposes)

					g_weaps[targ->toolweapclue].weapaquired = TRUE;
					g_numtools++;  // increment total number of acquired tools (for clue purposes)
					if (targ->toolweapclue == WP_HexRipper2) 
					{
						g_weaps[WP_HexRipper1].weapaquired = FALSE;
						if (g_selectedweap == WP_HexRipper1)
							g_selectedweap = WP_HexRipper2;
						playClue(2); //we're in info net playing ha159.wav
					}
					if (targ->toolweapclue == WP_AiresCom) 
					{
						playClue(13); //we're in data clns playing ha162.wav
					}
					g_blinktxt.numframes = NUMBLINKFRAMES;
				} 
				else if (targ->targettype == TARGET_CLUE) 
				{
					// Deal with sprites linked to this one
					for (links = targ->linkhead;
						 links != (TARGET *) NULL;
						 links = links->linked) 
					{
						if (links->status.state == (short) STATE_ALIVE)
							links->status.state = (short) STATE_DEAD;
						else if (links->status.state == (short) STATE_SLEEP) 
						{
							links->status.state = (short) STATE_ALIVE;
							SpriteAddOnScreen(-1, links);
						}
					}
					processSpecialClue(targ->toolweapclue); // in event.c
					targ->status.state = STATE_REST;
				}
			} else if(targ->toolweapclue > MAX_CYBTOOLS && targ->toolweapclue != TL_Circ)
				{
			      if(g_classtack[targ->eclass].pdamage[g_tools[g_selectedtool].toolnum])
				  g_damagedchannel = targ->channel;
				}
		}
	}
}

// ----------------------------------------------------------------------
//   checkWeapShot()
//
//  Check if player shots hit any targets, and damage or destroy them
//  as necessary.
// ----------------------------------------------------------------------

void checkWeapShot(short px, short py)
{
	short           spritex, spritey,spritemidx,spritemidy;
	long            spritearea;
	long            j;
	delayspriteptr  ds;
	spriteptr       s;
	TARGET          *targ, *links;
	long            ulx,uly,lrx,lry;
	static  long    nexplfr=-1, uppermid =-1, lowermid =-1;
	static  long    bigexpl=-1, smlexpl =-1,  midexpl=-1;
		

	nexplfr = (g_currentscenenumber > SC_GRWALL) ? NUMCYBEXPLFRAMES : NUMRWDEXPLFRAMES;
	bigexpl   = (g_currentscenenumber > SC_GRWALL) ? CBIG_EXPLOBASE : RBIG_EXPLOBASE;
	smlexpl   = (g_currentscenenumber > SC_GRWALL) ? CSML_EXPLOBASE : RSML_EXPLOBASE;
	midexpl   = (g_currentscenenumber > SC_GRWALL) ? CMID_EXPLOBASE : RMID_EXPLOBASE;

	uppermid  = g_sprsizes[g_currentscenenumber].average + 200;
	lowermid  = g_sprsizes[g_currentscenenumber].average - 200;

	if (g_SpritesOnScreen == (TARGET *) NULL)
		return;

		for (targ = g_SpritesOnScreen; targ != (TARGET *) NULL; targ = targ->onscreen) 
		{
			if (targ->status.state != (short) STATE_ALIVE)
				continue;

			if (targ->targettype != (long) TARGET_ENEMY)
				continue;


            if((g_currentscenenumber == SC_FINALC) &&
			   (targ->type == 'brnc'))
			     {
	              for (j = 0; j < g_spconds[SPC_FINALC3].numspecsprites; ++j)
		             if ((g_targstack[g_spconds[SPC_FINALC3].specsprites[j]].status.state) != (short) STATE_DEAD) 
		             break;

                  if(j < g_spconds[SPC_FINALC3].numspecsprites)
				    continue;
				 }

			ds = &g_pastein[targ->channel];
			spritex = ds->x;
			spritey = ds->y;
			s = ds->spritedata;
			spritemidx= spritex + (s->width  >> 1);
			spritemidy= spritey + (s->height >> 1);
			spritearea=(s->width * s->height);


			if((targ->bracketwidth  == BRACKET_WIDTH_FIN) &&
			   (targ->bracketheight == BRACKET_HEIGHT_FIN) &&
			   (spritearea < BRACKET_AREA_FIN))
			    {
				 ulx=((spritemidx-targ->bracketwidth)<0) ? 0 : (spritemidx-targ->bracketwidth);
				 uly=((spritemidy-targ->bracketheight)<0) ? 0 : (spritemidy-targ->bracketheight);
				 lrx=((spritemidx+targ->bracketwidth)>319) ? 319:(spritemidx+targ->bracketwidth);
				 lry=((spritemidy+targ->bracketheight)>319) ? 319 :(spritemidy+targ->bracketheight);
				}
			else
			   {
			    ulx = spritex;
			    uly = spritey;
				lrx = spritex + s->width;
				lry = spritey + s->height;
			   }

			if ((px > ulx) && (px < lrx) && (py > uly) && (py < lry)) 
			{
				// A hit!
				targ->status.life -= g_classtack[targ->eclass].pdamage[g_weaps[g_selectedweap].weapnum];
				for (links = targ->linkhead;
				     links != (TARGET *) NULL;
					 links = links->linked) 
					{
						if (links->type == targ->type)
				            links->status.life = targ->status.life;
					}
				// If the shot destroys the target, make it go boom!
				if (targ->status.life <= 0) 
				{
					// Killed the sucker.
					targ->status.state = (short) STATE_DEAD;
					// SpriteDelOnScreen(targ);
					if (g_currentscenenumber==SC_FIREWL && targ->type == 'butt')
						processSpecialClue(7); // spec. cond. for 1st ICB hit clue.


					// Deal with sprites linked to this one
					for (links = targ->linkhead;
						 links != (TARGET *) NULL;
						 links = links->linked) 
					{
						if (links->status.state == (short) STATE_ALIVE)
							links->status.state = (short) STATE_DEAD;
						else if (links->status.state == (short) STATE_SLEEP) 
						{
							links->status.state = (short) STATE_ALIVE;
							SpriteAddOnScreen(-1, links);
						}
					}

					spritearea = (s->width * s->height);

					if(spritearea < lowermid)
					  targ->status.explosionsize = smlexpl;
					else if(spritearea > uppermid)
					  targ->status.explosionsize = bigexpl;
					else 
					  targ->status.explosionsize = midexpl;


					targ->status.explosioncount = nexplfr;
					playSoundFX(S_EXPLOSION);

				}
				else if (g_classtack[targ->eclass].pdamage[g_weaps[g_selectedweap].weapnum])
				{
					g_damagedchannel = targ->channel;
				}
			}
		}
	}

	/* ------------------------------------------------------------------------
	 * initplayerinfo()
	 *
	 * Set the ship position, etc.  Also load various sprites and stuff,
	 * which logically should probably go in another function.
	 * ----------------------------------------------------------------------*/

int initplayerinfo()
{
	if (g_inputdevice == INPUT_JOY)
	{       
		g_joyplayer.x = (SHIP_MAX_RIGHT - SHIP_MAX_LEFT) / 2 + SHIP_MAX_LEFT;
		g_joyplayer.y = (SHIP_MAX_BOTTOM - SHIP_MAX_TOP) / 2 + SHIP_MAX_TOP;
		g_joyplayer.pitch = g_player.cpitch = 0;
		g_joyplayer.bank = g_player.cbank = 0;
	}

	g_player.x = (SHIP_MAX_RIGHT - SHIP_MAX_LEFT) / 2 + SHIP_MAX_LEFT;
	g_player.y = (SHIP_MAX_BOTTOM - SHIP_MAX_TOP) / 2 + SHIP_MAX_TOP;
	g_player.pitch = g_player.cpitch = 0;
	g_player.bank = g_player.cbank = 0;

	if (!g_coordbuf)
		loadcoords();

	if (g_currentscenenumber < SC_PORTAL)
	{
#ifdef CHUKWUWETA
		sprintf(g_buffer,"c:\\data\\rwdplayr.spr",g_cdrom);
#else
		sprintf(g_buffer,"%s\\data\\rwdplayr.spr",g_cdrom);
#endif
		LoadSprites(g_buffer,192,64);
	}
	else
	{
#ifdef CHUKWUWETA
		sprintf(g_buffer,"c:\\data\\cybplayr.spr",g_cdrom);
#else
		sprintf(g_buffer,"%s\\data\\cybplayr.spr",g_cdrom);
#endif
		LoadSprites(g_buffer,192,64);
	}

	initShots();
   setwindowoffset();
	return 1;
}

	// -------------------------------------------------------------------
	//   drawplayersprite()
	//
	//   Draw the player's ship and/or targeting cursor, as necessary.
	// -------------------------------------------------------------------

	drawplayersprite(u8 * buffer)
	{
		short   tcwidth = g_ramsprites[PSHIPBASE].width / 2;
		short   tcheight = g_ramsprites[PSHIPBASE].height / 2;

	// putting damage star here first so we can order things 
	// differently in xenon.c!  -MCR

	if((g_damgstar_x >=0) && 
	   (g_damgstar_y >=0))
	{
		 pastepSprite(g_ramsprites[DAMGSTAR],
				 g_damgstar_x,
				 g_damgstar_y,buffer);
		g_damgstar_x = -1;
		g_damgstar_y = -1;
   }    

	switch (g_viewmode) 
	{
		case VIEW_FIRSTPERSON:
			if (g_inputdevice == INPUT_JOY)
				pastepSprite(g_ramsprites[TARGETBASE],
						 g_player.x /*+ g_windowx*/ - tcwidth,
						 g_player.tcy /*+ g_windowy*/ - tcheight, buffer);
			else
				pastepSprite(g_ramsprites[TARGETBASE],
						 g_player.x /*+ g_windowx */- tcwidth,
						 g_player.y /*+ g_windowy */- tcheight, buffer);
			break;

		case VIEW_TOPDOWN:
			pastepSprite(g_ramsprites[TARGETBASE],
					 g_player.tcx /*+ g_windowx */- tcwidth,
					 g_player.tcy /*+ g_windowy*/ - tcheight, buffer);
			pastepSprite(g_ramsprites[TSHIPBASE + g_player.cursprite],
					 g_player.x - g_player.offx /*+ g_windowx*/,
					 g_player.y /*+ g_windowy*/ - g_player.offy, buffer);
			break;

		case VIEW_RWDSHIP:
			if (g_inputdevice == INPUT_JOY)
			{
				pastepSprite(g_ramsprites[TARGETBASE],
						 g_joyplayer.tcx /*+ g_windowx*/ - tcwidth,
						 g_joyplayer.tcy /*+ g_windowy*/ - tcheight, buffer);
				pastepSprite(g_ramsprites[PSHIPBASE + g_joyplayer.cursprite],
						 g_joyplayer.x - g_joyplayer.offx /*+ g_windowx*/,
						 g_joyplayer.y /*+ g_windowy*/ - g_joyplayer.offy, buffer);
			}
			else
			{
				pastepSprite(g_ramsprites[TARGETBASE],
						 g_player.tcx /*+ g_windowx*/ - tcwidth,
						 g_player.tcy /*+ g_windowy*/ - tcheight, buffer);
				pastepSprite(g_ramsprites[PSHIPBASE + g_player.cursprite],
						 g_player.x - g_player.offx /*+ g_windowx*/,
						 g_player.y /*+ g_windowy */- g_player.offy, buffer);
			}
			break;

		case VIEW_CYBSHIP:
			if (g_inputdevice == INPUT_JOY)
			{
				pastepSprite(g_ramsprites[TARGETBASE],
						 g_joyplayer.tcx /*+ g_windowx */ - tcwidth,
						 g_joyplayer.tcy /*+ g_windowy*/ - tcheight, buffer);
				pastepSprite(g_ramsprites[CSHIPBASE + g_joyplayer.cursprite],
						 g_joyplayer.x - g_joyplayer.offx/* + g_windowx*/,
						 g_joyplayer.y /*+ g_windowy*/ - g_joyplayer.offy, buffer);
			}
			else
			{
				pastepSprite(g_ramsprites[TARGETBASE],
						 g_player.tcx /*+ g_windowx*/ - tcwidth,
						 g_player.tcy /*+ g_windowy*/ - tcheight, buffer);
				pastepSprite(g_ramsprites[CSHIPBASE + g_player.cursprite],
						 g_player.x - g_player.offx /*+ g_windowx*/,
						 g_player.y /*+ g_windowy*/ - g_player.offy, buffer);
			}
			break;
		default:
			break;
	}
}

	// ---------------------------------------------------------------------
	//  processkeyboard()
	//
	// Process keypresses.  Note that we are using generic library functions
	// here, so there may be some unforseen repercussions.  Seems fine so far,
	// though.
	// ---------------------------------------------------------------------

processkeyboard()
{

#ifdef DEBUGGING_ON
 g_godpower = 0x77;
#endif
		if (g_keypressed) 
		{
			// NOTE g_keypressed contains the SCAN_CODE! not the actual char
			switch (g_keypressed) 
			{
			  case MAKE_1:
			  case MAKE_2:
			  case MAKE_3:
			  case MAKE_4:
			  case MAKE_5:
			  case MAKE_6:
			  case MAKE_7:
			  case MAKE_8:
			  case MAKE_9:
			   if(g_godpower != 0x77)
			    {g_keypressed = 0; break;}
				g_nextscenenumber = g_keypressed-1;
				g_killscene = TRUE;
			    break;
			  case MAKE_0:
			   if(g_godpower != 0x77)
			    {g_keypressed = 0; break;}
				g_nextscenenumber =0;
				g_killscene = TRUE;
			    break;
			  case MAKE_A:
			   if(g_godpower != 0x77)
			    {g_keypressed = 0; break;}
				g_nextscenenumber =10;
				g_killscene = TRUE;
			    break;
			   case MAKE_R:                 // Reset life
			   if(g_godpower != 0x77)
			    {g_keypressed = 0; break;}
				if (g_pauseon) 
				{
					g_keypressed = 0;
					break;
				}
				g_player.hitpoints = INITIAL_LIFE;
				break;

			case MAKE_V:                    // Deset life
			   if(g_godpower != 0x77)
			    {g_keypressed = 0; break;}
				if (g_pauseon) 
				{
					g_keypressed = 0;
					break;
				}
				g_player.hitpoints -= 100;
				break;

			case MAKE_J:
			   if(g_godpower != 0x77)
			    {g_keypressed = 0; break;}
				if (g_pauseon) 
				{
					g_keypressed = 0;
					break;
				}
				if ((g_branchframe = (g_curframe + 20)) >= g_numberofframes)
					g_branchframe = g_numberofframes - 1;
				break;

			case MAKE_P:
			   if(g_godpower != 0x77)
			    {g_keypressed = 0; break;}

				if (g_pauseon) 
				{
					g_keypressed = 0;
					break;
				}
				if (g_currentscenenumber > SC_COASTD)
					g_nextscenenumber = g_currentscenenumber - 1;
				g_killscene = TRUE;
				break;

			case MAKE_B:
			   if(g_godpower != 0x77)
			    {g_keypressed = 0; break;}

				if (g_pauseon) 
				{
					g_keypressed = 0;
					break;
				}
				if ((g_branchframe = (g_curframe - 20)) < 0)
					g_branchframe = 0;
				break;

			case MAKE_F:
			   if(g_godpower != 0x77)
			    {g_keypressed = 0; break;}

				if (g_pauseon) 
				{
					g_keypressed = 0;
					break;
				}
				if (g_currentscenenumber < SC_FINALC)
					g_nextscenenumber = g_currentscenenumber + 1;
				g_killscene = TRUE;
				break;

				// Change the currently selected weapon.
			case MAKE_SPACE:  case MAKE_ESC:

				if(g_cutsceneon == TRUE && 
					g_currentscenenumber == SC_FINALC && 
					g_endcut != -1)
				{
					g_branchframe = g_endcut;
					g_cutsceneon = FALSE;
					g_endcut = -1;
					break;
				}
				else if(g_cutsceneon == TRUE)
					break;

			   if(g_gameplaying == FALSE)
				{
				   g_killscene = TRUE;
				   break;
				}
				g_pauseon = ~g_pauseon;
				if (g_pauseon)
				{
					if(g_gotsound)
					{
					 if (AIL_sample_status(smp[CLUE]) != SMP_DONE)
							AIL_end_sample(smp[CLUE]);
					}
				}
				break;

				// Change the currently selected weapon.
			case MAKE_CTRL:
				if (g_pauseon) 
				{
					g_keypressed = 0;
					break;
				}
				changeWeap();
				break;

				// Change the currently selected tool.
			case MAKE_ALT:
				if (g_pauseon) 
				{
					g_keypressed = 0;
					break;
				}
				changeTool();
				break;

			case MAKE_X:
				// if(g_pauseon) {g_keypressed = 0; break;}
				g_leavegame = TRUE;
				break;

			// Replay the last clue
			case MAKE_F1:
				if (g_pauseon) 
				{
					g_keypressed = 0;
					break;
				}
				if (AIL_sample_status(smp[CLUE]) == SMP_DONE)
					playClue(REPLAY);
				break;

#if 0
			case MAKE_ESC:
				if (g_pauseon) 
				{
					g_keypressed = 0;
					break;
				}
				g_killscene = TRUE;
				break;
#endif

	#ifdef DEBUGGING_ON

			case MAKE_Z:                    // Go slow
				g_goslow = ~g_goslow;
				break;

			case MAKE_K:
				if (g_pauseon) 
				{
					g_keypressed = 0;
					break;
				}
				g_killscene = TRUE;
				break;

			case MAKE_S:
				if (g_pauseon) 
				{
					g_keypressed = 0;
					break;
				}
				debugSpeed++;
				if (debugSpeed > 5)
					debugSpeed = 0;
				break;
	#endif
			default:
				g_keypressed = 0;
				break;
			}
			g_keypressed = 0;
		}
		g_keypressed = 0;
		FWKeyboard_ClearBuffer();
		return(TRUE);
}

/*
 * changetool() - takes care of necessary actions caused by the
 *                                player pressing the leftshift button on
 *                                either the control pad or joystick.
 */

void changeTool(void)
{
	long gstl = g_selectedtool;

	if (g_currentscenenumber < SC_PORTAL)
		return;

	while (1) 
	{
		g_selectedtool = (g_selectedtool == TL_TraceCutter2) ? TL_DamageRepair : ++g_selectedtool;

		if (g_tools[g_selectedtool].toolaquired == TRUE)
			break;

		if (g_selectedtool == gstl)
			break;
	}
}

	/*
	 * changeWeap() - takes care of necessary actions caused by the
	 *                                player pressing the rightshift button on
	 *                                either the control pad or joystick.
	 */

	void changeWeap(void)
	{
		char                    maxweapons,
						startweapons;
		long                    gswp = g_selectedweap;

		if (g_currentscenenumber > SC_GRWALL) 
		{        /* In cyberspace */
			maxweapons = MAX_CYBWEAPONS;
			startweapons = WP_Cyclone;
		} 
		else 
		{                                       /* In real world */
			maxweapons = MAX_RWDWEAPONS;
			startweapons = WP_Thunderbolt;
		}

		while (1) 
		{
			g_selectedweap = (g_selectedweap >= maxweapons - 1) ? startweapons : ++g_selectedweap;
			if (g_weaps[g_selectedweap].weapaquired == TRUE)
				break;

			if (g_selectedweap == gswp)
				break;
		}
	}

// -----------------------------------------------------------------------
//  movetopdown()
//
//  Similar to the poorly-named findshipposition() function, but this is
//  for the VIEW_TOPDOWN mode.
// -----------------------------------------------------------------------

void movetopdown()
{
	int whichsprite;

	/* Adjust player position, velocity */
	g_deltax /= DXPERMICKEY;
	g_deltay /= DYPERMICKEY;
	if (g_deltax < -1 * MAXDX)
		g_deltax = -1 * MAXDX;
	if (g_deltax > MAXDX)
		g_deltax = MAXDX;
	if (g_deltay < -1 * MAXDY)
		g_deltay = -1 * MAXDY;
	if (g_deltay > MAXDY)
		g_deltay = MAXDY;
	g_player.dx += g_deltax;
	g_player.dy += g_deltay;
	g_player.x += g_player.dx;
	if (g_inputdevice == INPUT_MOUSE)
		g_player.y += g_player.dy;  // Note y-axis is NOT reversed
	else
		g_player.y -= g_player.dy;  // Note y-axis is NOT reversed

	/* Check boundaries */
	if (g_player.x < SHIP_MAX_LEFT) 
	{
		g_player.x = SHIP_MAX_LEFT;
		g_player.dx = 0;
	} 
	else if (g_player.x > SHIP_MAX_RIGHT) 
	{
		g_player.x = SHIP_MAX_RIGHT;
		g_player.dx = 0;
	}
	if (g_player.y < SHIP_MAX_TOP) 
	{
		g_player.y = SHIP_MAX_TOP;
		g_player.dy = 0;
	} 
	else if (g_player.y > SHIP_MAX_BOTTOM) 
	{
		g_player.y = SHIP_MAX_BOTTOM;
		g_player.dy = 0;
	}
	g_player.bank = g_player.dx / 3;
	if (g_player.bank < -3)
		g_player.bank = -3;
	if (g_player.bank > 3)
		g_player.bank = 3;
	if (g_player.cbank < g_player.bank)
		g_player.cbank++;
	else if (g_player.cbank > g_player.bank)
		g_player.cbank--;
	/* Apply Friction */
	g_player.dx = (3 * g_player.dx) / 4;
	g_player.dy = (3 * g_player.dy) / 4;

		/* Determine location of targeting cursor */
	g_player.tcx = g_player.x + 1;
	g_player.tcy = g_player.y - 40;

	if (g_player.tcy < 6)
		g_player.tcy = 6;
	else if (g_player.tcy > 150)
		g_player.tcy = 150;


	/* Zero out movement counters */
	g_deltax = 0;
	g_deltay = 0;

		/* Adjust sprite number, offsets */
	whichsprite = 3 + g_player.cbank;
	if (whichsprite < 0)
		whichsprite = 0;
	else if (whichsprite > 6)
		whichsprite = 6;
	g_player.offx = g_topcoordbuf[(whichsprite) * 6 + 2];
	g_player.offy = g_topcoordbuf[(whichsprite) * 6 + 3];
	g_player.cursprite = whichsprite;
	g_player.leftwingx = g_player.x - g_player.offx + g_topcoordbuf[whichsprite * 6];
	g_player.leftwingy = g_player.y - g_player.offy + g_topcoordbuf[whichsprite * 6 + 1];
	g_player.rightwingx = g_player.x - g_player.offx + g_topcoordbuf[whichsprite * 6 + 4];
	g_player.rightwingy = g_player.y - g_player.offy + g_topcoordbuf[whichsprite * 6 + 5];
}


testcollisionmap(u8 * picbuf)
{
	extern u8         *g_collisionmap;
	u8                       *pmap = g_collisionmap;
	long                    bitpos = 0,
					row,
					col,
					i,
					j;
	for (row = 0; row < 200 / 8; row++) 
	{
		for (col = 0; col < 352 / 8; col++) 
		{
			if ((*pmap) & (1 << bitpos)) 
			{
				u8                       *p = picbuf;
				for (i = 0; i < 8; i += 2) 
				{
					for (j = 0; j < 8; j += 2) 
					{
						*p = SHOTCOLORBASE + 1;
						p += 2;
					}
					p += 352 * 2 - 8;
				}
			}
			picbuf += 8;
			bitpos++;
			if (bitpos > 7) 
			{
				pmap++;
				bitpos = 0;
			}
		}
		picbuf += 7 * 352;
	}
	return(TRUE);
}

// -----------------------------------------------------------------
//   dodamage()
//
//  Damage the player, check for death, damage sound effects, etc.
// -----------------------------------------------------------------

docollisiondamage(long damage, long effect)
{
//CSC June 17 1996 Make Canyon easier
 static char do_damage = 0;


    do_damage = ~do_damage;

    if(!do_damage)
	  return;

	g_player.hitpoints -= damage;

	//g_player.hitpoints -= 100;
	if (g_currentscenenumber == SC_CANYON)
		g_typeofdeath = CN_DEATH_BY_COLLISION;
	else if (g_currentscenenumber == SC_PDEFEN)
	 {
	   if((g_curframe > 680) && (g_curframe < 780))
		g_typeofdeath = PD_DEATH_BY_BIGSCREWS;
	   else
		g_typeofdeath = PD_DEATH_BY_GENERALSHOT;
	 }

	if (g_player.hitpoints < 0) 
	{
		g_player.hitpoints = 0;
		return;
	}
	g_shipshake = 4;
	switch (effect) 
	{
#if 0
	case EFFECT_LEFT_HIT:
		startani(&g_ramsprites[EXPLOBASE], g_player.leftwingx + g_windowx,
				 g_player.leftwingy + g_windowy, 2, 0, 0);
		break;
	case EFFECT_RIGHT_HIT:
		startani(&g_ramsprites[EXPLOBASE], g_player.rightwingx + g_windowx,
				 g_player.rightwingy + g_windowy, 2, 0, 0);
#endif
	default:break;
		break;
	}
}

checkforcollision(u8 * buf)
{
	extern u8         *g_collisionmap;
	u8                       *pmapLeft;
	u8                       *pmapRight;
	long                    offsetLeft;
	long                    offsetRight;
	long                    x,
					y;
	static int        hitRight = 0;
	static int        hitLeft = 0;

	// Kills Warning
	buf = buf;

	if (!g_collisionmap)
		return(TRUE);

	x = (g_player.leftwingx + g_windowx) / 8;
	y = (g_player.leftwingy + g_windowy) / 8;
	offsetLeft = (44 * y + x);
	pmapLeft = g_collisionmap + offsetLeft / 8;

	x = (g_player.rightwingx + g_windowx) / 8;
	y = (g_player.rightwingy + g_windowy) / 8;
	offsetRight = (44 * y + x);
	pmapRight = g_collisionmap + offsetRight / 8;


	if ((*pmapLeft) & (1 << (offsetLeft % 8))) 
	{
		hitLeft++;
	} 
	else 
	{
		hitLeft = 0;
	}

	if ((*pmapRight) & (1 << (offsetRight % 8))) 
	{
		hitRight++;
	} 
	else 
	{
		hitRight = 0;
	}


//CSC June18 1996
#if 0
	if (hitLeft && hitRight) 
	{
		if (hitLeft > hitRight)
			docollisiondamage(1, EFFECT_LEFT_HIT);
		else
			docollisiondamage(1, EFFECT_RIGHT_HIT);

		// FOR DEBUG ONLY
//		if (hitLeft == hitRight)
//			docollisiondamage(1, EFFECT_LEFT_HIT);
		// END DEBUG
	} 
	else 
	{
#endif

     if (hitLeft)  docollisiondamage(1, EFFECT_LEFT_HIT);
else if (hitRight) docollisiondamage(1, EFFECT_RIGHT_HIT);

//CSC June 17 1996.
#if 0
	}
#endif

	return(TRUE);
}

unsigned char Get_Scan_Code(void)
{
	unsigned char   inpc;
// use BIOS functions to retrieve the scan code of the last pressed key
// if a key was pressed at all, otherwise return 0
// Checks for CNTRL and ALT

	extern unsigned char Asm_GetScanCode(void);
#pragma aux Asm_GetScanCode = \
	"mov ah,02h" \
	"int 16h" \
		"and ah,0x04" \
		"jz no_ctrl" \
		"mov al, 29" \
		"xor ah,ah" \
		"jmp done" \
		"no_ctrl:" \
		"and ah,0x08" \
		"jz check_others" \
		"mov al, 56" \
		"xor ah,ah" \
		"jmp done" \
		"check_others:" \
		"mov ah,01h" \
		"int 16h" \
		"jz buffer_empty" \
		"mov ah,00h" \
		"int 16h" \
		"mov al,ah" \
		"xor ah,ah" \
		"jmp done" \
		"buffer_empty:" \
		"xor ax,ax" \
		"jmp done" \
		"done:";

	inpc = Asm_GetScanCode();

	return (inpc);
}                                                          // end Get_Scan_Code

void updateanimations(u8 * buffer)
{
	u8  *bufstart = buffer;
	static  char   arrow_right=0;
	long arrow_x, arrow_y, msgx, msgy;
		
	if ((g_blinktxt.numframes) && (g_blinktxt.tswitch)) 
	{
		if (g_currentscenenumber < SC_PORTAL)
		{
			g_textcol = RW_RED;
			msgy = 145;
		}
		else
		{
			g_textcol = CY_GREEN;
			msgy = 130;
		}
		msgx = ( 160 - ((strlen(g_blinktxt.blinktext)/2)*5) );
		printx(msgx, msgy, g_blinktxt.blinktext, bufstart);
		--g_blinktxt.numframes;
		g_blinktxt.tswitch = ~g_blinktxt.tswitch;
	} 
	else if (g_blinktxt.numframes) 
	{
		--g_blinktxt.numframes;
		g_blinktxt.tswitch = ~g_blinktxt.tswitch;
	}

	if(g_branchwarn)
	{
		 if(arrow_right)
		  {
		   arrow_x = (g_incyberspace) ? CYB_BR_ARROWR_X : REL_BR_ARROWR_X;
		   arrow_y = (g_incyberspace) ? CYB_BR_ARROWR_Y : REL_BR_ARROWR_Y;
		   pastepSprite(g_ramsprites[BR_ARROWR],
						arrow_x,
						arrow_y,
						bufstart);
		 }
		 else
		 {
		   arrow_x = (g_incyberspace) ? CYB_BR_ARROWL_X : REL_BR_ARROWL_X;
		   arrow_y = (g_incyberspace) ? CYB_BR_ARROWL_Y : REL_BR_ARROWL_Y;
		   pastepSprite(g_ramsprites[BR_ARROWL],
						arrow_x,
						arrow_y,
						bufstart);
		 }
		 arrow_right = ~arrow_right;
	 }
}
